package ex3.reversi;

import java.util.ArrayList;
import ex3.board.ConfigClass;

/**
 * This class is manage the logic of the reversi game.  
 * 
 * @author Maxim
 *
 */
public class GameManager {

	private int[][] _board;
	private int _turn;
	
	private int _player1Score;
	private int _player2Score;
	private int _gameMode;
	private IComputerStrategy _strategy;
	private boolean _isGameOver;
	

	public GameManager(int gameMode, int turn){
		
		_strategy = new ComputerSmartStrategy();
		
		this._gameMode = gameMode;
		this._isGameOver = false;
		this._board  = new int[ConfigClass.BOARD_SIZE][ConfigClass.BOARD_SIZE];
		this._turn = turn;
		this._player1Score = 2;
		this._player2Score = 2;
		
		for (int i = 0; i < ConfigClass.BOARD_SIZE; i++)
			for(int j = 0; j < ConfigClass.BOARD_SIZE; j++){
				this._board[i][j] = ConfigClass.EMPTY_CELL;
			}
		
		this._board[3][3] = ConfigClass.WHITE_PIECE;
		this._board[4][4] = ConfigClass.WHITE_PIECE;
		
		this._board[3][4] = ConfigClass.BLACK_PIECE;
		this._board[4][3] = ConfigClass.BLACK_PIECE;
		

		if(this._gameMode == ConfigClass.ONE_PLAYER_MODE & this._turn == ConfigClass.COMPUTER_TURN){
			computerDoMove();
		}
	}



	public void move(int i, int j){
		
		
		 doMove(i, j);
		 if(this._gameMode == ConfigClass.ONE_PLAYER_MODE){
						 
			 computerDoMove();	
		 }
		 
		if(!canMove()){
			this._isGameOver = true;
			return;
		}
	
	}


	/**
	 * 
	 */
	private void computerDoMove() {
		

		StrategyDecision tDecision ;
		tDecision=_strategy.DescidePlay(_board);
		doMove(tDecision.get_i(),tDecision.get_j());
	}



	/**
	 * @param i
	 * @param j
	 */
	private void doMove(int i, int j) {
		ArrayList<Piece> tPiecesToPut = new ArrayList<Piece>();
		
		playNorth(i,j,tPiecesToPut);
		playNorthEast(i,j,tPiecesToPut);
		playEast(i,j,tPiecesToPut);
		playSouthEast(i,j,tPiecesToPut);
		playSouth(i,j,tPiecesToPut);
		playSouthWest(i,j,tPiecesToPut);
		playWest(i,j,tPiecesToPut);
		playNorthWest(i,j,tPiecesToPut);
				
		if(tPiecesToPut.size() > 0){
			changeBoard(tPiecesToPut);
			this._turn = 3 - this._turn;
		}
		
		updateResults();
	}
	
	
	private boolean playNorth(int i, int j, ArrayList<Piece> PiecesToPut ){
		
		if(this._board[i][j] != ConfigClass.EMPTY_CELL) return false;
		
		if (i == 1 | i == 0)
			return false;
		
		int tEnemyPieces = 0;
		int tUpIndex = i-1;
		ArrayList<Piece> tPossibleMove = new ArrayList<Piece>();
		
		tPossibleMove.add(new Piece(i, j));
		
		while (enemyPiece(tUpIndex, j)){
			tPossibleMove.add(new Piece(tUpIndex, j));
			tUpIndex--;
			tEnemyPieces++;
		}
		return tEnemyPieces > 0 &&  validCell(tUpIndex , j ) && this._board[tUpIndex][j] == this._turn
			&& PiecesToPut.addAll(tPossibleMove);
	}
	
	private boolean playNorthEast(int i, int j, ArrayList<Piece> PiecesToPut){
		
		int tI = i-1;
		int tJ = j+1;
		int tEnemyPieces = 0;
		if(this._board[i][j] != ConfigClass.EMPTY_CELL) return false;
		if (j == ConfigClass.BOARD_SIZE | j == ConfigClass.BOARD_SIZE  -1 )
			return false;
		
		if (i == 1 | i == 0 )
			return false;
		ArrayList<Piece> tPossibleMove = new ArrayList<Piece>();	
		tPossibleMove.add(new Piece(i, j));
	
		while (enemyPiece(tI, tJ)){	
			tPossibleMove.add(new Piece(tI, tJ));
			tI--;
			tJ++;
			tEnemyPieces++;
		}
		return tEnemyPieces > 0 && validCell(tI , tJ) && this._board[tI][tJ]  == this._turn &&
			PiecesToPut.addAll(tPossibleMove);
	}
	
	private boolean playEast(int i, int j, ArrayList<Piece> PiecesToPut){
		
		if(this._board[i][j] != ConfigClass.EMPTY_CELL) return false;
		if (j == ConfigClass.BOARD_SIZE | j == ConfigClass.BOARD_SIZE  -1 )
			return false;
		
		int tEnemyPieces = 0;
		int tJ = j+1;
		
		ArrayList<Piece> tPossibleMove = new ArrayList<Piece>();	
		tPossibleMove.add(new Piece(i, j));
		
		while (enemyPiece(i, tJ))	{
			tPossibleMove.add(new Piece(i, tJ));
			tJ++;
			tEnemyPieces++;
		}
		
		return tEnemyPieces > 0 && validCell(i, tJ) && this._board[i][tJ] == this._turn
			&& PiecesToPut.addAll(tPossibleMove);
	}
	
	private boolean playSouthEast(int i, int j, ArrayList<Piece> PiecesToPut){
		
		int tI = i+1;
		int tJ = j+1;
		int tEnemyPieces = 0;
		if(this._board[i][j] != ConfigClass.EMPTY_CELL) return false;
		if (i == ConfigClass.BOARD_SIZE | i == ConfigClass.BOARD_SIZE  -1 )
			return false;
		
		if (j == ConfigClass.BOARD_SIZE | j == ConfigClass.BOARD_SIZE  -1 )
			return false;
		ArrayList<Piece> tPossibleMove = new ArrayList<Piece>();	
		tPossibleMove.add(new Piece(i, j));
	
		while (enemyPiece(tI, tJ)){	
			tPossibleMove.add(new Piece(tI, tJ));
			tI++;
			tJ++;
			tEnemyPieces++;
		}
		return tEnemyPieces > 0 &&  validCell(tI, tJ) && this._board[tI][tJ]  == this._turn
			&& PiecesToPut.addAll(tPossibleMove);
	}
	
	private boolean playSouth(int i, int j, ArrayList<Piece> PiecesToPut){
		if(this._board[i][j] != ConfigClass.EMPTY_CELL) return false;
		if (i == ConfigClass.BOARD_SIZE | i == ConfigClass.BOARD_SIZE  - 1)
			return false;
		int tEnemyPieces = 0;
		int tI = i+1;
		ArrayList<Piece> tPossibleMove = new ArrayList<Piece>();	
		tPossibleMove.add(new Piece(i, j));
		while (enemyPiece(tI, j)){
			tPossibleMove.add(new Piece(tI, j));
			tI++;
			tEnemyPieces++;
		}
		
		return tEnemyPieces > 0 &&  validCell(tI, j) && this._board[tI][j] == this._turn
			&& PiecesToPut.addAll(tPossibleMove);
	}
	
	private boolean playSouthWest(int i, int j, ArrayList<Piece> PiecesToPut){
		int tEnemyPieces = 0;
		int tI = i+1;
		int tJ = j-1;
		if(this._board[i][j] != ConfigClass.EMPTY_CELL) return false;
		if (i == ConfigClass.BOARD_SIZE | i == ConfigClass.BOARD_SIZE  -1 )
			return false;
		
		if (j == 1 | j == 0 )
			return false;
		ArrayList<Piece> tPossibleMove = new ArrayList<Piece>();	
		tPossibleMove.add(new Piece(i, j));
		while (enemyPiece(tI, tJ)){	
			tPossibleMove.add(new Piece(tI, tJ));
			tI++;
			tJ--;
			tEnemyPieces++;
		}
		return tEnemyPieces > 0 &&  validCell(tI, tJ) && this._board[tI][tJ]  == this._turn
			&& PiecesToPut.addAll(tPossibleMove);
	}
	
	private boolean playWest(int i, int j, ArrayList<Piece> PiecesToPut){
		int tEnemyPieces = 0;
		if (j == 1 | j == 0 )
			return false;
		if(this._board[i][j] != ConfigClass.EMPTY_CELL) return false;
		int tJ = j-1;
		ArrayList<Piece> tPossibleMove = new ArrayList<Piece>();	
		tPossibleMove.add(new Piece(i, j));
		while (enemyPiece(i, tJ)){	
			tPossibleMove.add(new Piece(i, tJ));
			tJ--;
			tEnemyPieces++;
		}
		
		return tEnemyPieces > 0 &&   validCell(i, tJ) &&this._board[i][tJ] == this._turn
			&& PiecesToPut.addAll(tPossibleMove);
	}
	
	private boolean playNorthWest(int i, int j, ArrayList<Piece> PiecesToPut){
		int tEnemyPieces = 0;
		int tI = i-1;
		int tJ = j-1;
		if(this._board[i][j] != ConfigClass.EMPTY_CELL) return false;
		if (i == 0 | i == 1 )
			return false;
		
		if (j == 0 | j == 1 )
			return false;
		ArrayList<Piece> tPossibleMove = new ArrayList<Piece>();	
		tPossibleMove.add(new Piece(i, j));
		while (enemyPiece(tI, tJ)){	
			tPossibleMove.add(new Piece(tI, tJ));
			tI--;
			tJ--;
			tEnemyPieces++;
		}
		return tEnemyPieces > 0 &&  validCell(tI, tJ) && this._board[tI][tJ]  == this._turn
			&& PiecesToPut.addAll(tPossibleMove);
	}
	

	
	public boolean is_isGameOver() {
		return _isGameOver;
	}
	
		
	public int[][] get_board() {
		return _board;
	}



	public int get_turn() {
		return _turn;
	}



	public int get_player1Score() {
		return _player1Score;
	}



	public int get_player2Score() {
		return _player2Score;
	}
	
	
	private boolean enemyPiece(int i , int j){
		
		return this.validCell(i, j) && 
				this._board[i][j] != ConfigClass.EMPTY_CELL && this._board[i][j]!=this._turn;
		
	}
	
	private boolean validCell(int i, int j){
		
		return i < ConfigClass.BOARD_SIZE & i >= 0 & j < ConfigClass.BOARD_SIZE & j >= 0;
	}
	
	
	private void changeBoard(ArrayList<Piece> pieces){
		
		int tPiecesNumber = pieces.size();
		
		for(int i = 0; i < tPiecesNumber; i++){
			
			this._board[pieces.get(i).get_x()][pieces.get(i).get_y()] = this._turn;
			
		}
	}
	
	private void updateResults(){
		
		this._player1Score = 0;
		this._player2Score = 0;
		
		
		for (int i = 0; i < ConfigClass.BOARD_SIZE; i++)
			for(int j = 0; j < ConfigClass.BOARD_SIZE; j++){
				switch(this._board[i][j]){
					
					case ConfigClass.WHITE_PIECE:
						this._player1Score++;
						break;
					
					case ConfigClass.BLACK_PIECE:
						this._player2Score++;
						break;
				}
			}
		
	}
	
	
	private boolean canMove(){
		
		boolean tAnswer = false;
		ArrayList<Piece> tPiecesToPut = new ArrayList<Piece>();
		
		for(int i = 0; i < ConfigClass.BOARD_SIZE & !tAnswer; i++)
			for(int j = 0; j < ConfigClass.BOARD_SIZE & !tAnswer; j++){
				tAnswer = playNorth(i,j,tPiecesToPut); 
				tAnswer = tAnswer | playNorthEast(i,j,tPiecesToPut);
				tAnswer = tAnswer | playEast(i,j,tPiecesToPut);
				tAnswer = tAnswer | playSouthEast(i,j,tPiecesToPut);
				tAnswer = tAnswer | playSouth(i,j,tPiecesToPut);
				tAnswer = tAnswer | playSouthWest(i,j,tPiecesToPut);
				tAnswer = tAnswer | playWest(i,j,tPiecesToPut);
				tAnswer = tAnswer | playNorthWest(i,j,tPiecesToPut);
				
				if(tAnswer)
					System.out.println(i+ " "+ j);
			}
				
		return tAnswer;
	}
}
